package com.naiterui.ehp.bs.cms.modules.statistics.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.agent.ProvinceItemBO;
import com.naiterui.ehp.bp.bo.statistics.CustomOrderReportBO;
import com.naiterui.ehp.bp.bo.statistics.CustomProductReportBO;
import com.naiterui.ehp.bp.bo.statistics.CustomRecipelConsultReportBO;
import com.naiterui.ehp.bp.bo.statistics.CustomSeriesDataBO;
import com.naiterui.ehp.bp.bo.statistics.DataReportBO;
import com.naiterui.ehp.bp.bo.statistics.DataReportInviteBO;
import com.naiterui.ehp.bp.bo.statistics.DataReportProductBO;
import com.naiterui.ehp.bp.bo.statistics.DataReportRecipelBO;
import com.naiterui.ehp.bp.bo.statistics.DataReportSelectRecipelBO;
import com.naiterui.ehp.bp.bo.statistics.RecipelRankingBO;
import com.naiterui.ehp.bs.cms.common.utils.ReportUtil;
import com.naiterui.ehp.bs.cms.common.vo.PageParamsVO;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAgentMapper;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AsAreaCountMapper;
import com.naiterui.ehp.bs.cms.modules.statistics.mapper.AsAgentInviteCountMapper;
import com.naiterui.ehp.bs.cms.modules.statistics.mapper.AsOrderCountMapper;
import com.naiterui.ehp.bs.cms.modules.statistics.mapper.AsProductCountMapper;
import com.naiterui.ehp.bs.cms.modules.statistics.mapper.AsRecipelCountMapper;
import com.naiterui.ehp.bs.cms.modules.statistics.service.IStatisticsService;
import com.naiterui.ehp.bs.cms.modules.statistics.vo.AsRecipelConsultVO;
import com.naiterui.ehp.bs.cms.modules.statistics.vo.CustomOrderVO;
import com.naiterui.ehp.bs.cms.modules.statistics.vo.CustomProductVO;
import com.naiterui.ehp.bs.cms.modules.statistics.vo.DataReportInviteVO;
import com.naiterui.ehp.bs.cms.modules.statistics.vo.DataReportRecipelTotalVO;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 经纪人数据统计
 *
 * @author yangfuya
 * @since 2022/1/5
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StatisticsServiceImpl implements IStatisticsService {
    private final AsAgentInviteCountMapper asAgentInviteCountMapper;
    private final AsOrderCountMapper asOrderCountMapper;
    private final AsProductCountMapper asProductCountMapper;
    private final AsRecipelCountMapper asRecipelCountMapper;
    private final AsAreaCountMapper asAreaCountMapper;
    private final AgAgentMapper agAgentMapper;
    @Value("${ehp.domain.img}")
    private String imgDomain;

    @Override
    public CustomRecipelConsultReportBO getRecipelAndConsult(Long customId, Integer reportType, String reportDate) {
        CustomRecipelConsultReportBO reportBO = new CustomRecipelConsultReportBO();
        AsRecipelConsultVO recipelConsultTotal = asRecipelCountMapper.getRecipelConsultTotal(customId);
        if (recipelConsultTotal == null) {
            reportBO.setPecipelTotal(0);
            reportBO.setConsultTotal(0);
        } else {
            reportBO.setPecipelTotal(recipelConsultTotal.getRecipelTotal());
            reportBO.setConsultTotal(recipelConsultTotal.getConsultTotal() + recipelConsultTotal.getVideoTotal());
        }

        List<AsRecipelConsultVO> recipelConsult = asRecipelCountMapper.getRecipelConsult(customId,
            ReportUtil.getTypeFormat(reportType), ReportUtil.getDateFormat(reportType), reportDate);
        if (CollUtil.isEmpty(recipelConsult)) {
            reportBO.setDateList(Collections.emptyList());
            reportBO.setSeriesData(Collections.emptyList());
            reportBO.setSelectRecipel(0);
            reportBO.setSelectConsult(0);
            reportBO.setAvgPecipel(0D);
            reportBO.setAvgConsult(0D);
        } else {
            reportBO.setDateList(
                recipelConsult.stream().map(AsRecipelConsultVO::getGenerateDate).collect(Collectors.toList()));
            reportBO.setSeriesData(Arrays.asList(
                        CustomSeriesDataBO.builder().name("处方")
                            .data(recipelConsult.stream().map(AsRecipelConsultVO::getRecipelTotal)
                                .collect(Collectors.toList()))
                            .build(),
                        CustomSeriesDataBO
                            .builder().name("问诊").data(recipelConsult.stream()
                                .map(r -> r.getConsultTotal() + r.getVideoTotal()).collect(Collectors.toList()))
                            .build()));
            reportBO.setSelectRecipel(recipelConsult.stream().mapToInt(AsRecipelConsultVO::getRecipelTotal).sum());
            reportBO
                .setSelectConsult(recipelConsult.stream().mapToInt(r -> r.getConsultTotal() + r.getVideoTotal()).sum());
            reportBO.setAvgPecipel(handleAvg(
                recipelConsult.stream().mapToInt(AsRecipelConsultVO::getRecipelTotal).average().getAsDouble()));
            reportBO.setAvgConsult(handleAvg(recipelConsult.stream()
                .mapToInt(r -> r.getConsultTotal() + r.getVideoTotal()).average().getAsDouble()));
        }
        return reportBO;
    }

    @Override
    public CustomProductReportBO getProduct(Long customId, Integer reportType, String reportDate) {
        CustomProductReportBO reportBO = new CustomProductReportBO();
        Long productPriceTotal = asProductCountMapper.getProductPriceTotal(customId);
        reportBO.setTotalSales(productPriceTotal == null ? 0L : productPriceTotal);
        List<CustomProductVO> products = asProductCountMapper.getProductTotal(customId,
            ReportUtil.getTypeFormat(reportType), ReportUtil.getDateFormat(reportType), reportDate);
        if (CollUtil.isEmpty(products)) {
            reportBO.setDateList(Collections.emptyList());
            reportBO.setSeriesData(Collections.emptyList());
            reportBO.setSelectSalesVolume(0);
            reportBO.setAvgSalesVolume(0D);
        } else {
            reportBO.setDateList(products.stream().map(CustomProductVO::getGenerateDate).collect(Collectors.toList()));
            reportBO.setSeriesData(Collections.singletonList(CustomSeriesDataBO.builder().name("销售金额")
                .data(products.stream().map(CustomProductVO::getProductPriceTotal).collect(Collectors.toList()))
                .build()));
            reportBO.setSelectSalesVolume(products.stream().mapToInt(CustomProductVO::getProductPriceTotal).sum());
            reportBO.setAvgSalesVolume(
                handleAvg(products.stream().mapToInt(CustomProductVO::getProductPriceTotal).average().getAsDouble()));
        }
        return reportBO;
    }

    @Override
    public CustomOrderReportBO getOrder(Long customId, Integer reportType, String reportDate) {
        CustomOrderReportBO reportBO = new CustomOrderReportBO();
        Integer orderTotal = asOrderCountMapper.getOrder(customId);
        reportBO.setOrderTotal(orderTotal == null ? 0 : orderTotal);
        List<CustomOrderVO> orders = asOrderCountMapper.getOrderTotal(customId,
            ReportUtil.getTypeFormat(reportType),
            ReportUtil.getDateFormat(reportType), reportDate);
        if (CollUtil.isEmpty(orders)) {
            reportBO.setDateList(Collections.emptyList());
            reportBO.setSeriesData(Collections.emptyList());
        } else {
            reportBO.setDateList(orders.stream().map(CustomOrderVO::getGenerateDate).collect(Collectors.toList()));
            reportBO.setSeriesData(Collections.singletonList(CustomSeriesDataBO.builder().name("订单数量")
                .data(orders.stream().map(CustomOrderVO::getOrderTotal).collect(Collectors.toList())).build()));
        }
        return reportBO;
    }

    @Override
    public DataReportBO getDateReportIndex(Long agentId) {
        DataReportBO reportBO = new DataReportBO();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, -24);
        String today = dateFormat.format(calendar.getTime());
        calendar.set(Calendar.HOUR_OF_DAY, -24);
        String yesterday = dateFormat.format(calendar.getTime());
        getInviteQoq(agentId, today, yesterday, reportBO);
        getRecipelQoq(agentId, today, yesterday, reportBO);
        Long agentAreaId = asRecipelCountMapper.getAgentAreaId(agentId);
        List<RecipelRankingBO> recipelRankingList =
            asRecipelCountMapper.getRecipelRanking(agentAreaId, today);
        if (CollUtil.isNotEmpty(recipelRankingList)) {
            reportBO.setRankingList(recipelRankingList.stream().map(r -> {
                r.setAvatar(StrUtil.isNotBlank(r.getAvatar()) ? imgDomain + r.getAvatar() : "");
                return r;
            }).collect(Collectors.toList()));
        } else {
            reportBO.setRankingList(Collections.emptyList());
        }
        return reportBO;
    }

    @Override
    public DataReportRecipelBO getRecipelDateReport(Long agentId, Integer reportType, String reportDate) {
        DataReportRecipelBO reportRecipelBO = new DataReportRecipelBO();
        DataReportRecipelTotalVO totalDataReport = asRecipelCountMapper.getRecipelTotalDataReport(agentId);
        if (totalDataReport == null) {
            reportRecipelBO.setRecipelTotal(0);
            reportRecipelBO.setConsultTotal(0);
            reportRecipelBO.setOrderTotal(0);
            reportRecipelBO.setTotalSales(0);
        } else {
            reportRecipelBO
                .setRecipelTotal(totalDataReport.getRecipelTotal() == null ? 0 : totalDataReport.getRecipelTotal());
            reportRecipelBO
                .setConsultTotal((totalDataReport.getConsultTotal() == null ? 0 : totalDataReport.getConsultTotal())
                    + (totalDataReport.getVideoTotal() == null ? 0 : totalDataReport.getVideoTotal()));
            reportRecipelBO
                .setOrderTotal(totalDataReport.getOrderTotal() == null ? 0 : totalDataReport.getOrderTotal());
            reportRecipelBO.setTotalSales(
                (totalDataReport.getConsultPriceTotal() == null ? 0 : totalDataReport.getConsultPriceTotal())
                    + (totalDataReport.getVideoPriceTotal() == null ? 0 : totalDataReport.getVideoPriceTotal())
                    + (totalDataReport.getOrderPriceTotal() == null ? 0 : totalDataReport.getOrderPriceTotal()));
        }
        List<DataReportRecipelTotalVO> recipelDataReport = asRecipelCountMapper.getRecipelDataReport(agentId,
            ReportUtil.getTypeFormat(reportType), ReportUtil.getDateFormat(reportType), reportDate);
        if (CollUtil.isEmpty(recipelDataReport)) {
            reportRecipelBO.setDateList(Collections.emptyList());
            reportRecipelBO.setData(Collections.emptyList());
        } else {
            reportRecipelBO.setDateList(
                recipelDataReport.stream().map(DataReportRecipelTotalVO::getGenerateDate).collect(Collectors.toList()));
            reportRecipelBO.setData(
                recipelDataReport.stream().map(DataReportRecipelTotalVO::getRecipelTotal).collect(Collectors.toList()));
            reportRecipelBO
                .setSelectList(
                    recipelDataReport.stream()
                        .map(r -> DataReportSelectRecipelBO.builder()
                            .selectConsult(r.getConsultTotal() + r.getVideoTotal()).selectOrder(r.getOrderTotal())
                            .selectSalesVolume(
                                r.getConsultPriceTotal() + r.getVideoPriceTotal() + r.getOrderPriceTotal())
                            .build())
                        .collect(Collectors.toList()));
        }
        return reportRecipelBO;
    }

    @Override
    public DataReportInviteBO getInviteDataReport(Long agentId, Integer reportType, String reportDate) {
        DataReportInviteBO reportInviteBO = new DataReportInviteBO();
        DataReportInviteVO inviteTotal = asAgentInviteCountMapper.getInviteTotal(agentId);
        if (inviteTotal == null) {
            reportInviteBO.setInviteTotal(0);
            reportInviteBO.setAuthNumber(0);
            reportInviteBO.setUnauthNumber(0);
            reportInviteBO.setAuthingNumber(0);
            reportInviteBO.setNoPassNumber(0);
        } else {
            reportInviteBO.setInviteTotal(inviteTotal.getNewNumber() == null ? 0 : inviteTotal.getNewNumber());
            reportInviteBO.setAuthNumber(inviteTotal.getAuthNumber() == null ? 0 : inviteTotal.getAuthNumber());
            reportInviteBO.setUnauthNumber(inviteTotal.getUnauthNumber() == null ? 0 : inviteTotal.getUnauthNumber());
            reportInviteBO
                .setAuthingNumber(inviteTotal.getAuthingNumber() == null ? 0 : inviteTotal.getAuthingNumber());
            reportInviteBO.setNoPassNumber(inviteTotal.getNoPassNumber() == null ? 0 : inviteTotal.getNoPassNumber());
        }
        List<DataReportInviteVO> inviteList = asAgentInviteCountMapper.getInviteList(agentId,
            ReportUtil.getTypeFormat(reportType), ReportUtil.getDateFormat(reportType), reportDate);
        if (CollUtil.isEmpty(inviteList)) {
            reportInviteBO.setDateList(Collections.emptyList());
            reportInviteBO.setData(Collections.emptyList());
        } else {
            reportInviteBO
                .setDateList(inviteList.stream().map(DataReportInviteVO::getGenerateDate).collect(Collectors.toList()));
            reportInviteBO
                .setData(inviteList.stream().map(DataReportInviteVO::getNewNumber).collect(Collectors.toList()));
        }
        return reportInviteBO;
    }

    @Override
    public PageVO<DataReportProductBO> getProduct(PageParamsVO pageParamsVO, Long agentId, Integer reportType,
        String reportDate) {
        Page<DataReportProductBO> page =
            asProductCountMapper.getPage(pageParamsVO.getPage(), agentId, ReportUtil.getTypeFormat(reportType),
                reportDate);
        return PageVO.newBuilder().result(page.getRecords().stream().map(p -> {
            p.setProductImg(imgDomain + "/images/static/sku" + p.getProductImg());
            return p;
        }).collect(Collectors.toList())).pageNo(pageParamsVO.getPageNo())
            .pageSize(pageParamsVO.getPageSize()).totalCount((int)page.getTotal()).build();
    }

    @Override
    public List<ProvinceItemBO> getProviceTotal(Long areaId, String proviceAreaIStr, String year, String month) {
        List<String> proviceAreaIdList = Arrays.asList(proviceAreaIStr.split(","));
        String dateFormat = null;
        String reportDate = null;
        if (StrUtil.isAllNotBlank(year, month)) {
            dateFormat = ReportUtil.getTypeFormat(2);
            reportDate = year + "-" + month;
        } else if (StrUtil.isNotBlank(year)) {
            dateFormat = ReportUtil.getTypeFormat(1);
            reportDate = year;
        }
        List<ProvinceItemBO> proviceTotal =
            asAreaCountMapper.getProviceTotal(areaId, proviceAreaIdList, dateFormat, reportDate);
        return proviceTotal;
    }

    private void getInviteQoq(Long agentId, String today, String yesterday, DataReportBO reportBO) {
        Integer countTotal = asAgentInviteCountMapper.getInviteCountTotal(agentId);
        reportBO.setInviteTotal(countTotal == null ? 0 : countTotal);
        List<DataReportInviteVO> inviteCountList =
            asAgentInviteCountMapper.getInviteCountList(agentId, Arrays.asList(today, yesterday));
        Integer todayInvite = 0;
        Integer yesterdayInvite = 0;
        for (DataReportInviteVO data : inviteCountList) {
            if (today.equals(data.getGenerateDate())) {
                todayInvite = data.getNewNumber();
            } else {
                yesterdayInvite = data.getNewNumber();
            }
        }
        BigDecimal qoq = ReportUtil.getQoq(todayInvite, yesterdayInvite);
        reportBO.setYesterdayInvite(todayInvite);
        reportBO.setYesterdayInviteQoq(qoq.compareTo(BigDecimal.ZERO) < 0 ? "-" : "+");
        reportBO.setYesterdayInviteQoqValue((qoq + "%").replace("-", ""));
    }

    private void getRecipelQoq(Long agentId, String today, String yesterday, DataReportBO reportBO) {
        DataReportRecipelTotalVO dataReport = asRecipelCountMapper.getRecipelTotalDataReport(agentId);
        if (dataReport == null) {
            reportBO.setRecipelTotal(0);
            reportBO.setProductTotal(0);
        } else {
            Integer recipelTotal = dataReport.getRecipelTotal();
            Integer orderPriceTotal = dataReport.getOrderPriceTotal();
            reportBO.setRecipelTotal(recipelTotal == null ? 0 : recipelTotal);
            reportBO.setProductTotal(orderPriceTotal == null ? 0 : orderPriceTotal);
        }
        // 获取环比数据
        List<DataReportRecipelTotalVO> recipelCountList =
            asRecipelCountMapper.getRecipelCountList(agentId, Arrays.asList(today, yesterday));
        Integer todayRecipel = 0;
        Integer yesterdayRecipe = 0;
        Integer todayOrderPrice = 0;
        Integer yesterdayOrderPrice = 0;
        for (DataReportRecipelTotalVO data : recipelCountList) {
            if (today.equals(data.getGenerateDate())) {
                todayRecipel = data.getRecipelTotal();
                todayOrderPrice = data.getOrderPriceTotal().intValue();
            } else {
                yesterdayRecipe = data.getRecipelTotal();
                yesterdayOrderPrice = data.getOrderPriceTotal().intValue();
            }
        }
        BigDecimal recipelQoq = ReportUtil.getQoq(todayRecipel, yesterdayRecipe);
        reportBO.setYesterdayRecipel(todayRecipel);
        reportBO.setYesterdayRecipelQoq(recipelQoq.compareTo(BigDecimal.ZERO) < 0 ? "-" : "+");
        reportBO.setYesterdayRecipelQoqValue((recipelQoq + "%").replace("-", ""));
        BigDecimal productQoq = ReportUtil.getQoq(todayOrderPrice, yesterdayOrderPrice);
        reportBO.setYesterdayProduct(todayOrderPrice);
        reportBO.setYesterdayProductQoq(productQoq.compareTo(BigDecimal.ZERO) < 0 ? "-" : "+");
        reportBO.setYesterdayProductQoqValue((productQoq + "%").replace("-", ""));
    }

    private Double handleAvg(double avg) {
        BigDecimal bd = new BigDecimal(avg);
        bd = bd.setScale(2, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }
}
